home *** CD-ROM | disk | FTP | other *** search
/ Aminet 37 / Aminet 37 (2000)(Schatztruhe)[!][Jun 2000].iso / Aminet / comm / bbs / cit_src_AD08.lha / netmisc.c < prev    next >
C/C++ Source or Header  |  2000-03-09  |  64KB  |  2,480 lines

  1. /*
  2. *       netmisc.c
  3. *
  4. * Networking functions of miscellaneous type.
  5. */
  6. /*
  7. *       history
  8. *
  9. * 91Aug17 HAW  New comment style.
  10. * 86Aug20 HAW  History not maintained due to space problems.
  11. */
  12. #include "ctdl.h"
  13. #include <dos.h>
  14. /*
  15. *       contents
  16. *
  17. */
  18. /* #define NET_DEBUG 1  */
  19. /*
  20. *   External variable declarations in NET.C
  21. */
  22.  
  23.  
  24.  
  25. char    *SR_Sent;
  26. char    ErrBuf[100];    /* General buffer for error messages */
  27. label   HomeId;
  28. int   AnyIndex = 0;  /* tracks who to call between net sessions */
  29. FILE    *netLog, *netMisc, *netMsg;
  30. static char     UsedNetMsg;
  31. char    *nMsgTemplate = "netMsg.$$$";
  32. char    logNetResults = FALSE;
  33. char    inNet = NON_NET;
  34. AN_UNSIGNED     RecBuf[SECTSIZE + 5];
  35. int   callSlot;
  36. label   normed, callerName, callerId;
  37. logBuffer       *lBuf;
  38. int   PriorityMail = 0;
  39. char    *pollCall;
  40. int   LD_Delay = 60;
  41. static char *SupportedBauds[] =
  42.   {
  43.   "300", "3/12", "3/24", "3/48", "3/96", "3/14.4", "3/19.2", "3/38.4", "3/57.6"
  44.  
  45.   };
  46. /*
  47. * UntilNetSessions
  48. *
  49. * This is used to maintain a list of Until-Done net sessions as requested by
  50. * the sysop.  Each element contains information concerning which member net
  51. * is involved (only one can be specified) and how long the session should
  52. * last.
  53. */
  54. void ExplainNeed(int i, MULTI_NET_DATA x);
  55. void freeUNS();
  56. SListBase UntilNetSessions =
  57.   {
  58.   NULL, ChkTwoNumbers, NULL, freeUNS, NULL
  59.  
  60.   };
  61. /*
  62. *   External variable definitions for NET.C
  63. */
  64. extern CONFIG    cfg;   /* Lots an lots of variables    */
  65. extern NetBuffer netTemp;
  66. extern logBuffer logBuf;  /* Person buffer    */
  67. extern logBuffer logTmp;  /* Person buffer    */
  68. extern aRoom     roomBuf; /* Room buffer      */
  69. extern rTable    *roomTab;
  70. extern MessageBuffer   msgBuf;
  71. extern MessageBuffer   tempMess;
  72. extern NetBuffer netBuf;
  73. extern NetTable  *netTab;
  74. extern int       thisNet;
  75. extern char      onConsole;
  76. extern char      loggedIn;  /* Is we logged in?   */
  77. extern char      outFlag; /* Output flag      */
  78. extern char      haveCarrier; /* Do we still got carrier?     */
  79. extern char      modStat; /* Needed so we don't die       */
  80. extern char      WCError;
  81. extern int       thisRoom;
  82. extern int       thisLog;
  83. extern char      *confirm;
  84. extern char      heldMess;
  85. extern char      netDebug;
  86. extern char      netdebuglog;
  87. extern char      *AssignAddress;
  88. extern char      remoteSysop;
  89. extern char     *DomainFlags;
  90. /*
  91. * called_stabilize()
  92. *
  93. * This function attempts to stabilize communication on the receiver end.
  94. */
  95. char called_stabilize()
  96.   {
  97.   char retVal;
  98.   retVal = getNetBaud();  /* has to handle stroll, too. */
  99.   if (!gotCarrier())
  100.     {
  101.     killConnection();
  102.     retVal = FALSE;
  103.  
  104.     }
  105.   return retVal;
  106.  
  107.   }
  108. static int table[2][3] =
  109.   {
  110.     { 7, 13, 69 },
  111.     {68, 79, 35}
  112.  
  113.   };
  114. /*
  115. * check_for_init()
  116. *
  117. * This function looks for the networking initialization sequence.
  118. */
  119. char check_for_init(char mode)
  120.   {
  121.   int index;
  122.   int count, timeOut;
  123.   AN_UNSIGNED thisVal, lastVal;
  124.   index = (inNet == STROLL_CALL) ? 1 : 0;
  125.   lastVal = (mode) ? table[index][0] : 0;
  126.   timeOut = (INTERVALS / 2) * (25);
  127.   for (count = 0; count < timeOut; count++)
  128.     {
  129.     if (MIReady())
  130.       {
  131.       thisVal = inp();
  132.       if (thisVal == table[index][0])
  133.       lastVal = table[index][0];
  134.       else if (thisVal == table[index][1])
  135.         {
  136.         if (lastVal == table[index][0]) lastVal = table[index][1];
  137.         else  lastVal = 0;
  138.  
  139.         }
  140.       else if (thisVal == table[index][2])
  141.         {
  142.         if (lastVal == table[index][1])
  143.           {
  144.           lastVal = AckStabilize(index);
  145.           if (lastVal == ACK) return TRUE;
  146.           else if (lastVal == table[index][2])
  147.           return(char) (AckStabilize(index) == ACK);
  148.           else if (lastVal != table[index][0] &&
  149.           lastVal != table[index][1])
  150.           return (char)FALSE;
  151.  
  152.           }
  153.  
  154.         }
  155.  
  156.       }
  157.     else pause(2);
  158.  
  159.     }
  160.   return FALSE;
  161.  
  162.   }
  163. /*
  164. * AckStabilize()
  165. *
  166. * This function tries to stabilize with net caller.
  167. */
  168. int AckStabilize(int index)
  169.   {
  170.   int temp;
  171.   outMod(~(table[index][0]));
  172.   outMod(~(table[index][1]));
  173.   outMod(~(table[index][2]));
  174.   temp = receive(1);
  175.   if (cfg.BoolFlags.debug) splitF(netLog, "AckStabilize=%d\n",temp);
  176.   return temp;
  177.  
  178.   }
  179. /*
  180. * AddNetMsgs()
  181. *
  182. * This function integrates messages into the data base.  Options include
  183. * adding the net area or not to the filename and specifying the processing
  184. * function rather than being stuck with a standard processing function.
  185. * Usually the processing function will integrate messages into the message
  186. * data base, although it may do negative mail checking instead.
  187. */
  188. int AddNetMsgs(char *base, void (*procFn)(void), char zap, int roomNo,
  189. char AddNetArea)
  190.   {
  191.   char tempNm[80];
  192.   int count = 0;
  193.   extern char *READ_ANY;
  194.   if (AddNetArea)
  195.   makeSysName(tempNm, base, &cfg.netArea);
  196.   else
  197.   strCpy(tempNm, base);
  198.   if ((netMisc = safeopen(tempNm, READ_ANY)) == NULL)
  199.     {
  200.     return ERROR;
  201.  
  202.     }
  203.   getRoom(roomNo);
  204.   /* If reading for mail room, prepare a log buffer. */
  205.   if (roomNo == MAILROOM)
  206.   lBuf = &logTmp;
  207.   else
  208.   lBuf = NULL;
  209.   while (getMessage(getNetChar, TRUE, TRUE, TRUE))
  210.     {
  211.     count++;
  212.     if (strCmpU(cfg.nodeId + cfg.codeBuf, msgBuf.mborig) != SAMESTRING)
  213.     (*procFn)();
  214.  
  215.     }
  216.   fclose(netMisc);
  217.   if (zap == 1) unlink(tempNm);
  218.   else if (zap == 2 && count != 0) unlink(tempNm);
  219.   return count;
  220.  
  221.   }
  222. /*
  223. * getNetChar()
  224. *
  225. * This function gets a character from a network temporary file.  The file
  226. * should have been opened elsewhere.
  227. */
  228. int getNetChar()
  229.   {
  230.   int c;
  231.   c = fgetc(netMisc);
  232.   if (c == EOF) return -1;
  233.   return c;
  234.  
  235.   }
  236. /*
  237. * inMail()
  238. *
  239. * This function integrates a message into the message database.  It includes
  240. * recognizing bangmail, vortex activation, and bad word scanning.
  241. */
  242. void inMail()
  243.   {
  244.   extern SListBase BadPeople;
  245.   extern SListBase BadWords;
  246.   /* do we need any code here? */
  247.   if (thisRoom == MAILROOM &&
  248.   (strchr(msgBuf.mbto, '!') != NULL ||
  249.   strchr(msgBuf.mbauth, '!') != NULL))
  250.   MakeRouted();   /* Route.C */
  251.   else if (NotVortex())
  252.     {
  253.     if (cfg.BoolFlags.NetScanBad)
  254.       {
  255.       if (thisRoom != MAILROOM && SearchList(&BadWords, msgBuf.mbtext) != NULL)
  256.         {
  257.         extern char BadMessages[];
  258.  
  259.         DiscardMessage( strlen(BadMessages)? BadMessages : "discard");
  260.  
  261.         sPrintf(msgBuf.mbtext,
  262.         "Net message from %s @%s in %s discarded for decency reasons.",
  263.         msgBuf.mbauth, msgBuf.mboname,
  264.         (roomExists(msgBuf.mbroom)) ?
  265.         formRoom(roomExists(msgBuf.mbroom), FALSE, FALSE) :
  266.         msgBuf.mbroom);
  267.         netResult(msgBuf.mbtext);
  268.         return;
  269.  
  270.         }
  271.       if (thisRoom != MAILROOM && SearchList(&BadPeople, &msgBuf) != NULL)
  272.         {
  273.         extern char BadMessages[];
  274.  
  275.         DiscardMessage( strlen(BadMessages)? BadMessages : "discard");
  276.  
  277.         sPrintf(msgBuf.mbtext,
  278.         "Net message from %s @%s in %s discarded By Sysop Option.",
  279.         msgBuf.mbauth, msgBuf.mboname,
  280.         (roomExists(msgBuf.mbroom)) ?
  281.         formRoom(roomExists(msgBuf.mbroom), FALSE, FALSE) :
  282.         msgBuf.mbroom);
  283.         netResult(msgBuf.mbtext);
  284.         return;
  285.  
  286.         }
  287.  
  288.       }
  289.     if (AssignAddress != NULL)
  290.     strCpy(msgBuf.mbaddr, AssignAddress);
  291.     putMessage(&logBuf);
  292.  
  293.     }
  294.   else DiscardMessage("discard");
  295.  
  296.   }
  297. static int GoodCount, BadCount;
  298. /*
  299. * inRouteMail()
  300. *
  301. * This function handles incoming route mail.
  302. */
  303. void inRouteMail()
  304.   {
  305.   label oname, domain;
  306.   if (RecipientAvail())
  307.     {
  308.     inMail();
  309.  
  310.     }
  311.   if (BadCount)
  312.     {
  313.     sPrintf(lbyte(tempMess.mbtext), " on %s _ %s was undeliverable.",
  314.     cfg.nodeName + cfg.codeBuf,
  315.     cfg.codeBuf + cfg.nodeDomain);
  316.     strCpy(tempMess.mbto, msgBuf.mbauth);
  317.     strCpy(oname, msgBuf.mboname);
  318.     strCpy(domain, msgBuf.mbdomain);
  319.     strCpy(tempMess.mbauth, "Citadel");
  320.     strCpy(tempMess.mbroom, "Mail");
  321.     strCpy(tempMess.mbtime, Current_Time());
  322.     strCpy(tempMess.mbdate, formDate());
  323.     sPrintf(tempMess.mbId, "%lu", cfg.newest++ + 1);
  324.     ZeroMsgBuffer(&msgBuf);
  325.     MoveMsgBuffer(&msgBuf, &tempMess);
  326.     netMailOut(TRUE, UseNetAlias(oname, FALSE), domain, FALSE, -1);
  327.  
  328.     }
  329.  
  330.   }
  331. /*
  332. * RecipientAvail()
  333. *
  334. * This function checks to see if recipient is here.  This includes override
  335. * handling.
  336. */
  337. char RecipientAvail()
  338.   {
  339.   void RecAvWork(char *);
  340.   GoodCount = BadCount = 0;
  341.   if (msgBuf.mbdomain[0])
  342.     {
  343.     if (!HasOverrides(&msgBuf))
  344.       {
  345.       RecAvWork(msgBuf.mbto);
  346.  
  347.       }
  348.     else
  349.       {
  350.       RunList(&msgBuf.mbOverride, RecAvWork);
  351.  
  352.       }
  353.     return (char)GoodCount;
  354.  
  355.     }
  356.   return TRUE;
  357.  
  358.   }
  359. /*
  360. * RecAvWork()
  361. *
  362. * This function does the real work of RecipientAvailable() - split out to
  363. * better handle other recipients.
  364. */
  365. void RecAvWork(char *name)
  366.   {
  367.   if (PersonExists(name) == ERROR &&
  368.   strCmpU(msgBuf.mbauth, "Citadel") != SAMESTRING)
  369.     {
  370.     BadCount++;
  371.     if( logNetResults )splitF(netLog, "No recipient: %s\n", name);
  372.     if (BadCount == 1)
  373.     sPrintf(tempMess.mbtext, "Your message to %s", name);
  374.     else
  375.     sPrintf(lbyte(tempMess.mbtext), ", %s", name);
  376.  
  377.     }
  378.   else if (PersonExists(name) != ERROR ||
  379.   strCmpU(msgBuf.mbauth, "Citadel") != SAMESTRING)
  380.   GoodCount++;
  381.  
  382.   }
  383. /*
  384. * DiscardMessage()
  385. *
  386. * This function prints a message to a discard file.
  387. */
  388. void DiscardMessage(char *filename)
  389.   {
  390.   extern int outPut;
  391.   extern FILE *upfd;
  392.   extern char *APPEND_TEXT;
  393.   if (redirect(filename))
  394.     {
  395.     mPrintf("%s (%s)", formHeader(), msgBuf.mbsrcId);
  396.     doCR();
  397.     mFormat(msgBuf.mbtext);
  398.     doCR();
  399.     doCR();
  400.     undirect();
  401.  
  402.     }
  403.  
  404.   }
  405. char *kip = NULL;
  406. /*
  407. * netController()
  408. *
  409. * This is the main manager of a network session.  It is responsible for
  410. * scheduling calls, noticing incoming calls, exiting network sessions due
  411. * to timeouts or other events, forming error reports for the Aide> room,
  412. * etc.
  413. */
  414. #define unSetPoll()     free(pollCall)
  415. void mTrPrintf(char *,...);
  416. void netController(int NetStart, int NetLength, MULTI_NET_DATA whichNets,
  417. char mode, UNS_16 flags)
  418.   {
  419.   int x;
  420.   int searcher = 0, start, first;
  421.   SYS_FILE AideMsg;
  422.   long waitTime, InterCallDelay;
  423.   extern char *WRITE_TEXT, *READ_TEXT, *APPEND_TEXT;
  424.   extern void (*NetPrintTarget)();
  425.   SpecialMessage("Status:Network Controller");
  426.   if (cfg.BoolFlags.debug)
  427.      splitF(netLog, "netController(%d,%d, %ld, %d,%d)\n", NetStart, NetLength,whichNets, (int)mode, flags);
  428.   if (loggedIn) /* should only happen on mistake by sysop */
  429.   terminate( /* hangUp == */ TRUE, TRUE);
  430.   NetPrintTarget = mTrPrintf;
  431.   outFlag = OUTOK;    /* for discarding messages correctly */
  432.   inNet = mode;
  433.   setPoll();
  434.   switch (mode)
  435.     {
  436.     case ANYTIME_NET:
  437.     case UNTIL_NET:
  438.     if (!AnyCallsNeeded(whichNets))
  439.       {
  440.       inNet = NON_NET;
  441.       unSetPoll();
  442.       return;
  443.  
  444.       }
  445.     searcher = AnyIndex;    /* so we don't always start at front */
  446.     break;
  447.     case ANY_CALL:
  448.     while (MIReady()) inp();
  449.     break;
  450.  
  451.     }
  452.   InterCallDelay = (!(flags & LEISURELY)) ? 2l : 15l;
  453.   SR_Sent = (char *) GetDynamic(SHARED_ROOMS);
  454.   if (logNetResults)
  455.     {
  456.     makeSysName(AideMsg, "netlog.sys", &cfg.netArea);
  457.     if ((netLog = safeopen(AideMsg, APPEND_TEXT)) == NULL)
  458.     netResult("Couldn't open netLog");
  459.  
  460.     }
  461.   else  netLog = NULL;
  462.   loggedIn = FALSE;     /* Let's be VERY sure.  */
  463.   thisLog = -1;
  464.   splitF(netLog, "\nNetwork Session %s @ %s\n", formDate(), Current_Time());
  465.   SpecialMessage("Network Session");
  466.   logMessage(INTO_NET, "", 0);
  467.   modStat = haveCarrier = FALSE;
  468.   setTime(NetStart, NetLength);
  469.   makeSysName(AideMsg, nMsgTemplate, &cfg.netArea);
  470.   if ((netMsg = safeopen(AideMsg, WRITE_TEXT)) == NULL)
  471.   splitF(netLog, "WARNING: Can't open %s!!!!\n", AideMsg);
  472.   UsedNetMsg = FALSE;
  473.   x = timeLeft();
  474.   do
  475.     {
  476.     /* force at least one time through loop */
  477.     waitTime = (cfg.catChar % 5) + 1;
  478.     while (waitTime > minimum(5, (x/2) ) ) waitTime /= 2;
  479.     if (flags & LEISURELY)
  480.     for (startTimer(WORK_TIMER);
  481.     chkTimeSince(WORK_TIMER) < (waitTime * 60) &&
  482.     !KBReady();)
  483.       {
  484.       if (gotCarrier()) break;
  485.       else BeNice(NET_PAUSE);
  486.  
  487.       }
  488.     /* This will break us out of a network session if ESC is hit */
  489.     if (KBReady())
  490.     if (getCh() == SPECIAL) break;
  491.     /*
  492.     * In case someone calls while we're doing after-call processing.
  493.     */
  494.     while (gotCarrier())
  495.       {
  496.       modStat = haveCarrier = TRUE;
  497.       called();
  498.       /* CacheMessages(ALL_NETS, TRUE); */
  499.  
  500.       }
  501.     /* ok, make calls */
  502.     if (cfg.netSize != 0)
  503.       {
  504.       start = searcher;
  505.       do
  506.         {
  507.         if (needToCall(searcher, whichNets))
  508.           {
  509.           ExplainNeed(searcher, whichNets);
  510.           if (!HasPriorityMail(searcher))
  511.           CacheSystem(searcher, FALSE);
  512.           if (callOut(searcher))
  513.             {
  514.             caller();
  515.             if( logNetResults )splitF(netLog, "(%s)\n", Current_Time());
  516.             if (kip != NULL && netBuf.baudCode >= B_5)
  517.               {
  518.               moPuts(kip);
  519.               outMod('\r');
  520.               if( netDebug )splitF(netLog, "debug from modem:\n");
  521.               for (startTimer(WORK_TIMER); chkTimeSince(WORK_TIMER) < 5l || MIReady();)
  522.               splitF(netLog, "%c", inp());
  523.  
  524.               }
  525.             /* CacheMessages(ALL_NETS, TRUE); */
  526.  
  527.             }
  528.           for (startTimer(WORK_TIMER); !gotCarrier() &&
  529.           chkTimeSince(WORK_TIMER) < InterCallDelay;)
  530.           ;
  531.           while (gotCarrier())
  532.             {
  533.             modStat = haveCarrier = TRUE;
  534.             called();
  535.  
  536.             }
  537.           if (whichNets == PRIORITY_MAIL)
  538.             {
  539.             getNet(thisNet, &netBuf);
  540.             netBuf.MemberNets &= ~(PRIORITY_MAIL);
  541.             putNet(thisNet, &netBuf);
  542.  
  543.             }
  544.  
  545.           }
  546.         searcher = (searcher + 1) % cfg.netSize;
  547.         if (mode == ANYTIME_NET && timeLeft() < 0 &&
  548.         whichNets != PRIORITY_MAIL)
  549.         break;      /* maintain discipline */
  550.  
  551.         }
  552.       while (!KBReady() && searcher != start);
  553.  
  554.       }
  555.     if (mode == ANYTIME_NET || mode == UNTIL_NET)
  556.       {
  557.       if (!AnyCallsNeeded(whichNets)) break;
  558.  
  559.       }
  560.  
  561.     }
  562.   while ((x = timeLeft()) > 0);
  563.   splitF(netLog, "\nOut of Networking Mode (%s)\n", Current_Time());
  564.   for (x = 0; x < cfg.netSize; x++)
  565.   if (netTab[x].ntMemberNets & PRIORITY_MAIL)
  566.     {
  567.     getNet(x, &netBuf);
  568.     netBuf.MemberNets &= ~(PRIORITY_MAIL);
  569.     putNet(x, &netBuf);
  570.  
  571.     }
  572.   if (flags & REPORT_FAILURE)
  573.     {
  574.     if (AnyCallsNeeded(whichNets))
  575.       {
  576.       sPrintf(msgBuf.mbtext,
  577.       "The following systems could not be reached: ");
  578.       for (searcher = 0, first = 1; searcher < cfg.netSize; searcher++)
  579.       if (needToCall(searcher, whichNets))
  580.         {
  581.         if (!first) strCat(msgBuf.mbtext,", ");
  582.         first = FALSE;
  583.         getNet(searcher, &netBuf);
  584.         strCat(msgBuf.mbtext, netBuf.netName);
  585.  
  586.         }
  587.       strCat(msgBuf.mbtext, ".");
  588.       netResult(msgBuf.mbtext);
  589.  
  590.       }
  591.  
  592.     }
  593.   if (inNet == ANYTIME_NET)
  594.     {
  595.     AnyIndex = searcher;    /* so we can start from here later */
  596.  
  597.     }
  598.   fclose(netMsg);
  599.   netMsg = NULL;
  600.   /* Make the error and status messages generated into an Aide> msg */
  601.   makeSysName(AideMsg, nMsgTemplate, &cfg.netArea);
  602.   if (UsedNetMsg)
  603.     {
  604.     ZeroMsgBuffer(&msgBuf);
  605.     if (access(AideMsg, 4) == -1)
  606.       {
  607.       sPrintf(msgBuf.mbtext, "Where did '%s' go???", AideMsg);
  608.       aideMessage("Net Aide", FALSE);
  609.  
  610.       }
  611.     else
  612.       {
  613.       ingestFile(AideMsg, &msgBuf);
  614.       aideMessage("Net Aide", FALSE);
  615.  
  616.       }
  617.  
  618.     }
  619.   unlink(AideMsg);
  620.   modStat = haveCarrier = FALSE;
  621.   inNet = NON_NET;
  622.   if (logNetResults)
  623.     {
  624.     fclose(netLog);
  625.     netLog = NULL;
  626.  
  627.     }
  628.   unSetPoll();
  629.   ITL_DeInit();
  630.   free(SR_Sent);
  631.   logMessage(OUTOF_NET, "", 0);
  632.   startTimer(NEXT_ANYNET);      /* anytime net timer */
  633.   getRoom(LOBBY);
  634.  
  635.   }
  636. static int RunUntil;
  637. /*
  638. * setTime()
  639. *
  640. * This function sets up some global variables for the networker.
  641. */
  642. void setTime(int NetStart, int NetLength)
  643.   {
  644.   int yr, hr, mins, dy, temp;
  645.   char *mn;
  646.   startTimer(NET_SESSION);
  647.   if (NetLength == 0)
  648.   RunUntil = 0;
  649.   else
  650.     {
  651.     getCdate(&yr, &mn, &dy, &hr, &mins);
  652.     temp = (hr * 60) + mins;
  653.     RunUntil = 60 * (NetLength - abs(temp - NetStart));
  654.  
  655.     }
  656.  
  657.   }
  658. /*
  659. * timeLeft()
  660. *
  661. * This function does a rough estimate of how much time left and returns it.
  662. */
  663. int timeLeft()
  664.   {
  665.   int elapsed;
  666.   elapsed = chkTimeSince(NET_SESSION);
  667.   if (elapsed > RunUntil) return 0;
  668.   return (((RunUntil - elapsed) / 60) + 1);
  669.  
  670.   }
  671. /*
  672. * callOut()
  673. *
  674. * This function attempts to call some other system.
  675. */
  676. char callOut(int i)
  677.   {
  678.   getNet(callSlot = i, &netBuf);
  679.   if( logNetResults )splitF(netLog, "Calling %s @ %s (%s): ",
  680.   netBuf.netName, netBuf.netId, Current_Time());
  681.   strCpy(normed, netBuf.netId);   /* Cosmetics */
  682.   strCpy(callerId, netBuf.netId);
  683.   strCpy(callerName, netBuf.netName);
  684.   if (makeCall(TRUE, NO_MENU)) return modStat = haveCarrier = TRUE;
  685.   killConnection();   /* Take SmartModem out of call mode   */
  686.   if( logNetResults )splitF(netLog, "No luck.\n");
  687.   return FALSE;
  688.  
  689.   }
  690. /*
  691. * moPuts()
  692. *
  693. * This function puts a string out to modem without carr check.
  694. */
  695. void moPuts(char *s)
  696.   {
  697.   while (*s)
  698.     {
  699.     pause(5);
  700.     outMod(*s++);
  701.  
  702.     }
  703.  
  704.   }
  705. /*
  706. * netMessage()
  707. *
  708. * This function will send message via net.  This is a userland function.
  709. */
  710. int netMessage(int uploading)
  711.   {
  712.   if (!NetValidate(TRUE)) return FALSE;
  713.   ZeroMsgBuffer(&msgBuf);
  714.   if (!netInfo(TRUE)) return FALSE;
  715.   return procMessage(uploading, FALSE);
  716.  
  717.   }
  718. /*
  719. * writeNet()
  720. *
  721. * This function writes nodes on the net to the screen.  Options include
  722. * showing only local systems and with or without their ids.
  723. */
  724. void writeNet(char idsAlso, char LocalOnly)
  725.   {
  726.   int rover, count = 0, len;
  727.   int i;
  728.   outFlag = OUTOK;
  729.   mPrintf("Systems on the net:\n ");
  730.   doCR();
  731.   for (rover = 0; outFlag != OUTSKIP && rover < cfg.netSize; rover++)
  732.     {
  733.     if (netTab[rover].ntflags.in_use &&
  734.     (!LocalOnly || netTab[rover].ntflags.local))
  735.       {
  736.       getNet(rover, &netBuf);
  737.       if ((idsAlso || netBuf.MemberNets & ALL_NETS))
  738.         {
  739.         /* mPrintf("%-22s", netBuf.netName); */
  740.         mPrintf("%s", netBuf.netName);
  741.         if (idsAlso)
  742.           {
  743.           #ifdef TURBO_C_VSPRINTF_BUG
  744.           SpaceBug(22 - strLen(netBuf.netName));   /* EEEESH */
  745.           mPrintf("%-22s%-16s%-8s", netBuf.netId,
  746.           (needToCall(rover, ALL_NETS)) ? "<need to call>" : "",
  747.           SupportedBauds[netBuf.baudCode]);
  748.           #else
  749.           mPrintf("%*c%-22s%-16s%-8s", 22 - strLen(netBuf.netName),
  750.           ' ', netBuf.netId,
  751.           (needToCall(rover, ALL_NETS)) ? "<need to call>" : "",
  752.           SupportedBauds[netBuf.baudCode]);
  753.           #endif
  754.           if (netBuf.nbflags.OtherNet) mPrintf("O");
  755.           else if (!(netBuf.MemberNets & ALL_NETS))
  756.           mPrintf("d");
  757.           if (netBuf.nbflags.MassTransfer)
  758.           mPrintf("F");
  759.           mPrintf(" M:");
  760.           for (i = 0; i < 32; i++)
  761.             {
  762.             if ((1l << i) & netBuf.MemberNets) mPrintf("%d ", i + 1);
  763.             };
  764.           doCR();
  765.  
  766.           }
  767.         else
  768.           {
  769.           if (strLen(netBuf.nbShort) != 0)
  770.             {
  771.             mPrintf(" (%s)", netBuf.nbShort);
  772.             len = strLen(netBuf.nbShort) + 3;
  773.  
  774.             }
  775.           else len = 0;
  776.           /* mPrintf(", "); */
  777.           if (++count % 3 == 0)
  778.             {
  779.             count = 0;
  780.             doCR();
  781.  
  782.             }
  783.           else
  784.             {
  785.             #ifdef TURBO_C_VSPRINTF_BUG
  786.             SpaceBug(28 - (len + strLen(netBuf.netName)));   /* EEEESH */
  787.             #else
  788.             mPrintf("%*c", 28 - (len + strLen(netBuf.netName)), ' ');
  789.             #endif
  790.  
  791.             }
  792.  
  793.           }
  794.  
  795.         }
  796.  
  797.       }
  798.  
  799.     }
  800.   if (!idsAlso)
  801.   WriteDomainContents();
  802.  
  803.   }
  804. /*
  805. * netStuff()
  806. *
  807. * This function handles main net menu.
  808. */
  809. void netStuff()
  810.   {
  811.   extern char *who_str;
  812.   extern char ForceNet;
  813.   TwoNumbers  tmp;
  814.   char  work[50];
  815.   label       who;
  816.   int   logNo;
  817.   MenuId  id, id2;
  818.   long  Redials, duration;
  819.   char *Net_Prompt = "\nNet Menu\n ";
  820.   char  *NetMiscOpts[] =
  821.     {
  822.     "A(dd node to netlist) ", "C(redit setting)               ", "D(ial system)\n",
  823.     "E(dit a node)         ", "I(nitiate Anytime Net Session) ", "L(ocal list)\n",
  824.     "N(et privileges)      ", "P(riority Mail)                ", "R(equest File)\n",
  825.     "S(end File)           ", "U(ntil Done Net Sessions)      ", "V(iew net list)\n",
  826.     "X(Exit)               ", "Y(toggle NetLog)               ", "Z(toggle NetDebug\n",
  827.     "W(toggle Write Modem traffic)\n",
  828.     #ifdef ZNEEDED
  829.     "Z",
  830.     #endif
  831.     ""
  832.  
  833.     };
  834.   int AdminPriorityMail(char *line);
  835.   /* If we don't net, don't allow this. */
  836.   if (!cfg.BoolFlags.netParticipant)
  837.     {
  838.     SysopInfoReport(NO_MENU, "Networking is disabled on this installation.\n ");
  839.     return ;
  840.  
  841.     }
  842.   id = RegisterSysopMenu("netopt.mnu", NetMiscOpts,Net_Prompt);
  843.   do
  844.     {
  845.     outFlag = OUTOK;
  846.     RegisterThisMenu("netopt.mnu", NetMiscOpts);
  847.     SysopMenuPrompt(id, "\n Net function: ");
  848.     switch (GetSysopMenuChar(id))
  849.       {
  850.       case ERROR:
  851.       case 'X':
  852.       CloseSysopMenu(id);
  853.       return;
  854.       case 'Y':  /* toggle net log flag */
  855.         logNetResults = ( logNetResults ) ? FALSE : TRUE;
  856.         mPrintf("Network log is turned %s\n ",(logNetResults) ? "on ":"off");
  857.         break;
  858.       case 'W':  /* toggle writing modem traffic to ram file */
  859.         netdebuglog = ( netdebuglog ) ? FALSE : TRUE;
  860.         mPrintf("Modem Debug log is turned %s(ram:debug.modem)\n ",(netdebuglog) ? "on ":"off");
  861.         break;
  862.       case 'Z':  /* toggle net debug flag */
  863.         netDebug = ( netDebug ) ? FALSE : TRUE;
  864.         mPrintf("Network Debug is turned %s\n ",(netDebug) ? "on ":"off");
  865.         mPrintf("Network log is turned %s\n ",(logNetResults) ? "on ":"off");
  866.         break;
  867.       case 'P':
  868.       getList(AdminPriorityMail, "Systems and Priority Mail",
  869.       NAMESIZE, TRUE);
  870.       break;
  871.       case 'I':
  872.       ForceAnytime();
  873.       sPrintf(work, "now %s.\n ", ForceNet ? "ON" : "OFF");
  874.       SysopInfoReport(id, work);
  875.       break;
  876.       case 'R':   /* File requests */
  877.       SysopRequestString(id, "SYSTEM", who, sizeof who, 0);
  878.       if (!ReqNodeName(NULL, who, NULL, FALSE, FALSE, FALSE,
  879.       FALSE, TRUE, &netBuf))
  880.       break;
  881.       fileRequest();
  882.       break;
  883.       case 'S':   /* File transmissions */
  884.       SysopRequestString(id, "SYSTEM", who, sizeof who, 0);
  885.       if (!ReqNodeName(NULL, who, NULL, FALSE, FALSE, FALSE,
  886.       FALSE, TRUE, &netBuf))
  887.       break;
  888.       getSendFiles(id, who);
  889.       break;
  890.       case 'C':   /* Set users' LD credits */
  891.       if ((logNo = GetUser(who, &logTmp, TRUE)) == ERROR ||
  892.       logNo == cfg.MAXLOGTAB) break;
  893.       sPrintf(work, "Currently %d credits.", logTmp.credit);
  894.       SysopInfoReport(id, work);
  895.       logTmp.credit = (int) SysopGetNumber(id, "HWMYCR", 0l, 1000l);
  896.       sPrintf(work, "Set to %d.", logTmp.credit);
  897.       SysopInfoReport(id, work);
  898.       if (loggedIn  &&  strCmpU(logBuf.lbname, who) == SAMESTRING)
  899.       logBuf.credit = logTmp.credit;
  900.       putLog(&logTmp, logNo);
  901.       break;
  902.       case 'D':   /* Primitive dial out ability.  Don't get excited */
  903.       if (!onConsole) break;
  904.       if (gotCarrier())
  905.         {
  906.         /* carrier already?  just jump in */
  907.         CloseSysopMenu(id);
  908.         interact(FALSE);
  909.         id = RegisterSysopMenu("netopt.mnu", NetMiscOpts, Net_Prompt);
  910.         break;
  911.  
  912.         }
  913.       /* Get node to call, if none specified abort */
  914.       SysopRequestString(id, "SYSTEM", who, sizeof who, 0);
  915.       if (!ReqNodeName(NULL, who, NULL, FALSE, TRUE, FALSE, FALSE,
  916.       TRUE, &netBuf))
  917.         {
  918.         break;
  919.  
  920.         }
  921.       /* How many times should we try to call? */
  922.       if ((Redials = SysopGetNumber(id, "REDIAL", 0l,
  923.       65000l)) <= 0l)
  924.       Redials = 1l;       /* allow empty C/R to generate 1. */
  925.       /* Modem should be disabled since we're in CONSOLE mode. */
  926.       id2 = SysopContinual(netBuf.netName, "DIALIT", 50, 13);
  927.       EnableModem(FALSE);
  928.       for (; Redials > 0l; Redials--)
  929.         {
  930.         /* if successful call, start chattin'! */
  931.         if (makeCall(FALSE, id2))
  932.           {
  933.           SysopCloseContinual(id2);
  934.           id2 = NO_MENU;
  935.           CloseSysopMenu(id);
  936.           mputChar(BELL);
  937.           interact(FALSE);
  938.           id = RegisterSysopMenu("netopt.mnu", NetMiscOpts,Net_Prompt);
  939.           break;
  940.  
  941.           }
  942.         /* This handles an abort from kbd */
  943.         if (KBReady())
  944.           {
  945.           getCh();
  946.           /* Hope this turns off modem */
  947.           outMod(' '); pause(2);
  948.           DisableModem(FALSE);
  949.           break;
  950.  
  951.           }
  952.         /* printf("Failed\n"); */
  953.         /* Let modem stabilize for a moment. */
  954.         for (startTimer(WORK_TIMER);chkTimeSince(WORK_TIMER) < 3l; )
  955.         ;
  956.  
  957.         }
  958.       SysopCloseContinual(id2);
  959.       /*
  960.       * If we don't have carrier disable the modem.  We have this
  961.       * check in case sysop wants to perform download within
  962.       * Citadel.
  963.       */
  964.       if (!gotCarrier())
  965.         {
  966.         DisableModem(FALSE);
  967.         modStat = haveCarrier = FALSE;
  968.  
  969.         }
  970.       break;
  971.       case 'V':   /* View the net list. */
  972.       CloseSysopMenu(id);
  973.       doCR();
  974.       writeNet(TRUE, FALSE);
  975.       if (NeedSysopInpPrompt()) modIn();
  976.       id = RegisterSysopMenu("netopt.mnu", NetMiscOpts, Net_Prompt);
  977.       break;
  978.       case 'L':
  979.       CloseSysopMenu(id);
  980.       writeNet(TRUE, TRUE);
  981.       if (NeedSysopInpPrompt()) modIn();
  982.       id = RegisterSysopMenu("netopt.mnu", NetMiscOpts, Net_Prompt);
  983.       break;
  984.       case 'A':   /* Add a new node to the list */
  985.       addNetNode();
  986.       break;
  987.       case 'E':   /* Edit a node that is on the list */
  988.       SysopRequestString(id, "EDITSY", who, sizeof who,0);
  989.       if (!ReqNodeName(NULL, who, NULL, FALSE, TRUE, FALSE, TRUE, TRUE,
  990.       &netBuf))
  991.       break;
  992.       CloseSysopMenu(id);
  993.       editNode();
  994.       id = RegisterSysopMenu("netopt.mnu", NetMiscOpts, Net_Prompt);
  995.       break;
  996.       case 'N':   /* Give someone net privileges. */
  997.       NetPrivs(who);
  998.       break;
  999.       case 'U':
  1000.       id2 = SysopContinual(" Net Session ", "", 30, 4);
  1001.       SysopContinualString(id2, "MEMBER", work, 3, 0);
  1002.       tmp.first = atoi(work);
  1003.       if (tmp.first < 1 || tmp.first > MAX_NET - 1)
  1004.         {
  1005.         if (strLen(work) != 0)
  1006.         SysopError(id2, "Illegal Member Net");
  1007.  
  1008.         }
  1009.       else
  1010.         {
  1011.         if (SearchList(&UntilNetSessions, &tmp) != NULL)
  1012.           {
  1013.           SysopInfoReport(NO_MENU, "Net session deactivated.\n");
  1014.           KillData(&UntilNetSessions, &tmp);
  1015.  
  1016.           }
  1017.         else
  1018.           {
  1019.           SysopContinualString(id2, "DURATI", work, 4, 0);
  1020.           duration = atol(work);
  1021.           if (duration < 1l)
  1022.           SysopError(id2, "Illegal Duration");
  1023.           else
  1024.           AddData(&UntilNetSessions,MakeTwo(tmp.first,duration),
  1025.           NULL, FALSE);
  1026.  
  1027.           }
  1028.  
  1029.         }
  1030.       SysopCloseContinual(id2);
  1031.       break;
  1032.       #ifdef ZNEEDED
  1033.       case 'Z':
  1034.       inNet = NORMAL_NET;
  1035.       AddNetMsgs("tempmail.$$$", inMail, FALSE, MAILROOM, TRUE);
  1036.       inNet = NON_NET;
  1037.       break;
  1038.       #endif
  1039.  
  1040.       }
  1041.  
  1042.     }
  1043.   while (onLine());
  1044.  
  1045.   }
  1046. /*
  1047. * AdminPriorityMail()
  1048. *
  1049. * This handles the administration of priority mail.
  1050. */
  1051. int AdminPriorityMail(char *system)
  1052.   {
  1053.   if (searchNameNet(system, &netBuf) == ERROR)
  1054.     {
  1055.     SysopError(NO_MENU, "No such system\n");
  1056.  
  1057.     }
  1058.   else
  1059.     {
  1060.     if (!(netBuf.nbflags.normal_mail ||
  1061.     netBuf.nbflags.HasRouted ||
  1062.     DomainFlags[thisNet]))
  1063.       {
  1064.       SysopError(NO_MENU, "No outgoing mail.\n");
  1065.       return TRUE;
  1066.  
  1067.       }
  1068.     else if ((netBuf.MemberNets & PRIORITY_MAIL))
  1069.       {
  1070.       SysopInfoReport(NO_MENU, "Priority mail deactivated.\n");
  1071.       PriorityMail--;
  1072.       netBuf.MemberNets &= ~(PRIORITY_MAIL);
  1073.  
  1074.       }
  1075.     else
  1076.       {
  1077.       PriorityMail++;
  1078.       netBuf.MemberNets |= (PRIORITY_MAIL);
  1079.  
  1080.       }
  1081.     putNet(thisNet, &netBuf);
  1082.  
  1083.     }
  1084.   return TRUE;
  1085.  
  1086.   }
  1087. /*
  1088. * NetPrivs()
  1089. *
  1090. * This will setup net privs for someone.
  1091. */
  1092. void NetPrivs(label who)
  1093.   {
  1094.   int logNo, result;
  1095.   if ((logNo = GetUser(who, &logTmp, TRUE)) == ERROR) return;
  1096.   if (logNo == cfg.MAXLOGTAB)
  1097.     {
  1098.     result = DoAllQuestion("GVNTPR","TANTPR");
  1099.     if (result == ERROR) return;
  1100.     for (logNo = 0; logNo < cfg.MAXLOGTAB; logNo++)
  1101.       {
  1102.       getLog(&logTmp, logNo);
  1103.       if (!onConsole) mPrintf(".");
  1104.       if (logTmp.lbflags.L_INUSE && logTmp.lbflags.NET_PRIVS != result)
  1105.         {
  1106.         logTmp.lbflags.NET_PRIVS = result;
  1107.         putLog(&logTmp, logNo);
  1108.  
  1109.         }
  1110.  
  1111.       }
  1112.     return;
  1113.  
  1114.     }
  1115.   Output_Citadel_Message((logTmp.lbflags.NET_PRIVS) ? "USRNNT" : "USRNET",
  1116.   (long)who, NULL, NULL);
  1117.   if (!SysopGetYesNo(NO_MENU, NULL, "CONFRM"))   return;
  1118.   logTmp.lbflags.NET_PRIVS = !logTmp.lbflags.NET_PRIVS;
  1119.   if (strCmpU(logTmp.lbname, logBuf.lbname) == SAMESTRING)
  1120.   logBuf.lbflags.NET_PRIVS = logTmp.lbflags.NET_PRIVS;
  1121.   putLog(&logTmp, logNo);
  1122.  
  1123.   }
  1124. static char AddedFiles;
  1125. /*
  1126. * getSendFiles()
  1127. *
  1128. * This will get the files from the sysop to send to another system.
  1129. */
  1130. void getSendFiles(MenuId id, label sysName)
  1131.   {
  1132.   SYS_FILE       sysFile;
  1133.   char     temp[10];
  1134.   extern char    *APPEND_ANY;
  1135.   sPrintf(temp, "%d.sfl", thisNet);
  1136.   makeSysName(sysFile, temp, &cfg.netArea);
  1137.   if ((upfd = safeopen(sysFile, APPEND_ANY)) == NULL)
  1138.     {
  1139.     SysopPrintf(id, "Couldn't open %s for update?\n ", sysFile);
  1140.     return ;
  1141.  
  1142.     }
  1143.   sPrintf(msgBuf.mbtext, "Files to send to %s", sysName);
  1144.   AddedFiles = FALSE;
  1145.   getList(addSendFile, msgBuf.mbtext, 126, TRUE);
  1146.   fclose(upfd);
  1147.   if (AddedFiles)
  1148.     {
  1149.     netBuf.nbflags.send_files = TRUE;
  1150.     putNet(thisNet, &netBuf);
  1151.  
  1152.     }
  1153.  
  1154.   }
  1155. /*
  1156. * addSendFile()
  1157. *
  1158. * This is a work function, called indirectly by getList().
  1159. */
  1160. int addSendFile(char *Files)
  1161.   {
  1162.   struct fl_send sendWhat;
  1163.   extern MenuId GetListId;
  1164.   if (sysGetSendFilesV2(GetListId, Files, &sendWhat))
  1165.     {
  1166.     putSLNet(sendWhat, upfd);
  1167.     AddedFiles = TRUE;
  1168.  
  1169.     }
  1170.   return TRUE;
  1171.  
  1172.   }
  1173. /*
  1174. * addNetNode()
  1175. *
  1176. * This adds a node to the net listing.
  1177. */
  1178. void addNetNode()
  1179.   {
  1180.   int searcher, gen;
  1181.   char  goodAnswer, found;
  1182.   extern char *ALL_LOCALS;
  1183.   MenuId id;
  1184.   id = SysopContinual("", "", 2 * NAMESIZE, 5);
  1185.   for (searcher = 0; searcher < cfg.netSize; searcher++)
  1186.   if (netTab[searcher].ntflags.in_use == FALSE) break;
  1187.   if (searcher != cfg.netSize)
  1188.     {
  1189.     getNet(searcher, &netBuf);
  1190.     found = TRUE;
  1191.     gen = (netBuf.nbGen + 1) % NET_GEN;
  1192.  
  1193.     }
  1194.   else
  1195.     {
  1196.     found = FALSE;
  1197.     gen = 0;
  1198.  
  1199.     }
  1200.   killNetBuf(&netBuf);
  1201.   zero_struct(netBuf);  /* Useful initialization       */
  1202.   initNetBuf(&netBuf);
  1203.   /* Get a unique name */
  1204.   do
  1205.     {
  1206.     SysopContinualString(id, "SYSTEM", netBuf.netName, NAMESIZE, 0);
  1207.     if (strLen(netBuf.netName) == 0)
  1208.       {
  1209.       SysopCloseContinual(id);
  1210.       return;
  1211.  
  1212.       }
  1213.     if ((goodAnswer = strCmpU(ALL_LOCALS, netBuf.netName)) == 0)
  1214.     SysopError(id, "Sorry, reserved name\n ");
  1215.     else if ((goodAnswer = searchNameNet(netBuf.netName, &netTemp)==ERROR) == 0)
  1216.       {
  1217.       sPrintf(msgBuf.mbtext, "Sorry, %s is already in use.\n ",
  1218.       netBuf.netName);
  1219.       SysopError(id, msgBuf.mbtext);
  1220.  
  1221.       }
  1222.     else if (strchr(netBuf.netName, '_') != NULL)
  1223.       {
  1224.       goodAnswer = FALSE;
  1225.       SysopError(id, "Please don't use '_' in the system name.\n ");
  1226.  
  1227.       }
  1228.  
  1229.     }
  1230.   while (!goodAnswer);
  1231.   /* Get a unique ID */
  1232.   do
  1233.     {
  1234.     goodAnswer = TRUE;
  1235.     SysopContinualString(id, "SYSTID", netBuf.netId, NAMESIZE, 0);
  1236.     if (strLen(netBuf.netId) == 0)
  1237.       {
  1238.       SysopCloseContinual(id);
  1239.       return;
  1240.  
  1241.       }
  1242.     if (searchNet(netBuf.netId, &netTemp) != ERROR)
  1243.       {
  1244.       sPrintf(msgBuf.mbtext, "Sorry, %s is already in use.\n ",
  1245.       netBuf.netId);
  1246.       SysopError(id, msgBuf.mbtext);
  1247.       goodAnswer = FALSE;
  1248.  
  1249.       }
  1250.  
  1251.     }
  1252.   while (!goodAnswer);
  1253.   netBuf.baudCode = (int) SysopGetNumber(id, "BAUDST", 0l, 8l);
  1254.   netBuf.nbflags.local  = SysopGetYesNo(id, NULL, "ISSYSL");
  1255.   netBuf.nbflags.in_use = TRUE;
  1256.   netBuf.MemberNets   = 1;     /* Default */
  1257.   netBuf.nbGen    = gen;   /* Update generation #  */
  1258.   netBuf.nbRoute    = -1;
  1259.   netBuf.nbflags.RouteTo  = TRUE;
  1260.   netBuf.nbflags.RouteFor = TRUE;
  1261.   if (!found)
  1262.     {
  1263.     if (cfg.netSize != 0)
  1264.     netTab = (NetTable *)
  1265.     realloc(netTab, sizeof (*netTab) * ++cfg.netSize);
  1266.     else
  1267.     netTab = (NetTable *)
  1268.     GetDynamic(sizeof(*netTab) * ++cfg.netSize);
  1269.     searcher = cfg.netSize - 1;
  1270.     netTab[searcher].netTRooms = (SharedRoom *) GetDynamic(SR_BULK);
  1271.  
  1272.     }
  1273.   putNet(searcher, &netBuf);
  1274.   InitVNode(searcher);
  1275.   DomainInit(FALSE);    /* so we can redirect easily enough */
  1276.   SysopCloseContinual(id);
  1277.  
  1278.   }
  1279. /*
  1280. * addNetMem()
  1281. *
  1282. * This adds nets to this system's list.
  1283. */
  1284. int addNetMem(char *netnum)
  1285.   {
  1286.   int num;
  1287.   MULTI_NET_DATA temp;
  1288.   num = atoi(netnum);
  1289.   if (num < 1 || num > MAX_NET - 1)
  1290.     {
  1291.     SysopError(NO_MENU, "There are only 31 nets to choose from.\n");
  1292.     return TRUE;
  1293.  
  1294.     }
  1295.   temp = 1l;
  1296.   temp <<= (num-1);
  1297.   netBuf.MemberNets |= temp;
  1298.   return TRUE;
  1299.  
  1300.   }
  1301. /*
  1302. * subNetMem()
  1303. *
  1304. * This takes nets from a system's list.
  1305. */
  1306. int subNetMem(char *netnum)
  1307.   {
  1308.   int num;
  1309.   MULTI_NET_DATA temp;
  1310.   num = atoi(netnum);
  1311.   if (num < 1 || num > MAX_NET - 1)
  1312.     {
  1313.     SysopError(NO_MENU, "There are only 31 nets to choose from.");
  1314.     return TRUE;
  1315.  
  1316.     }
  1317.   temp = 1l;
  1318.   temp <<= (num-1);
  1319.   temp = ~temp;
  1320.   netBuf.MemberNets &= temp;
  1321.   return TRUE;
  1322.  
  1323.   }
  1324. /*
  1325. * editNode()
  1326. *
  1327. * This function will edit a net node.
  1328. */
  1329. void editNode()
  1330.   {
  1331.   label  temp2;
  1332.   char   title[50], work[50], temp[NAMESIZE*3];
  1333.   int    place, compress;
  1334.   MenuId id;
  1335.   char   exttemp;
  1336.   char   *NetEditOpts[] =
  1337.     {
  1338.     "A(ccess setting)  ", "B(aud code change)    ", "C(ondensed name)\n",
  1339.     "D(ownload toggle) ", "E(xternal Dialer)     ", "F(ast Transfers)\n",
  1340.     "I(D change)       ", "K(ill node from list) ", "L(ocal setting)\n",
  1341.     "M(ember Nets)     ", "N(ame change)         ", "O(thernet toggle)\n",
  1342.     "P(asswords)       ", "R(ooms shared)        ", "S(pine settings)\n",
  1343.     "V(alues)          ", "X(Exit)\n",
  1344.     #ifdef NEEDED
  1345.     "ZKludge",
  1346.     #endif
  1347.     ""
  1348.  
  1349.     };
  1350.   place = thisNet;    /* this is really a kludge, but for now will serve */
  1351.   if (!NeedSysopInpPrompt())  /* rather icky, really.  fix someday? */
  1352.   NodeValues(NO_MENU);
  1353.   sPrintf(title, "\nEditing %s\n", netBuf.netName);
  1354.   id = RegisterSysopMenu("netedit.mnu", NetEditOpts, title);
  1355.   while (onLine())
  1356.     {
  1357.     outFlag = OUTOK;
  1358.     sPrintf(work, "\n (%s) edit fn: ", netBuf.netName);
  1359.     SysopMenuPrompt(id, work);
  1360.     switch (GetSysopMenuChar(id))
  1361.       {
  1362.       case ERROR:
  1363.       case 'X':
  1364.       putNet(place, &netBuf);
  1365.       CloseSysopMenu(id);
  1366.       return;
  1367.       case 'E':
  1368.       exttemp = netBuf.nbflags.ExternalDialer;
  1369.       if ((netBuf.nbflags.ExternalDialer =
  1370.       SysopGetYesNo(id, NULL, "USEDIL")))
  1371.         {
  1372.         SysopRequestString(id, "DIALER",netBuf.access,sizeof netBuf.access,0);
  1373.         }
  1374.       else if (exttemp) /* clear old information */
  1375.       netBuf.access[0] = 0;
  1376.       break;
  1377.       case 'A':
  1378.       SysopRequestString(id, "ACCESS", netBuf.access,
  1379.       sizeof netBuf.access, 0);
  1380.       break;
  1381.       case 'B':
  1382.       netBuf.baudCode = (int) SysopGetNumber(id, "BAUDST", 0l, 8l);
  1383.       break;
  1384.       case 'C':
  1385.       temp[0] = temp[1] = temp[2] = '\0';
  1386.       SysopRequestString(id, "CONSNM", temp, 3, 0);
  1387.       if (searchNameNet(temp, &netTemp) != ERROR)
  1388.         {
  1389.         sPrintf(work, "'%s' is already in use.", temp);
  1390.         SysopError(id, work);
  1391.  
  1392.         }
  1393.       else
  1394.       strCpy(netBuf.nbShort, temp);
  1395.       break;
  1396.       case 'D':
  1397.       sPrintf(work, "for %s %s.\n ",
  1398.       netBuf.netName, netBuf.nbflags.NoDL ? "ON" : "OFF");
  1399.       SysopInfoReport(id, work);
  1400.       netBuf.nbflags.NoDL = !netBuf.nbflags.NoDL;
  1401.       break;
  1402.       case 'F':
  1403.       netBuf.nbflags.MassTransfer = !netBuf.nbflags.MassTransfer;
  1404.       if (netBuf.nbflags.MassTransfer)
  1405.         {
  1406.         /* kludges - next major release make into char */
  1407.         netBuf.nbflags.Zoo = FALSE;
  1408.         netBuf.nbflags.Zip = FALSE;
  1409.         netBuf.nbflags.Lha = FALSE;
  1410.         netBuf.nbflags.Arc = FALSE;
  1411.         if ((compress = GetUserCompression()) == NO_COMP)
  1412.           {
  1413.           netBuf.nbflags.MassTransfer = FALSE;
  1414.           RegisterThisMenu("netedit.mnu", NetEditOpts);
  1415.           break;
  1416.  
  1417.           }
  1418.         switch (compress)
  1419.           {
  1420.           case ZIP_COMP: netBuf.nbflags.Zip = TRUE;break;
  1421.           case ZOO_COMP: netBuf.nbflags.Zoo = TRUE;break;
  1422.           case ARC_COMP: netBuf.nbflags.Arc = TRUE;break;
  1423.           case LHA_COMP: netBuf.nbflags.Lha = TRUE;break;
  1424.  
  1425.           }
  1426.         RegisterThisMenu("netedit.mnu", NetEditOpts);
  1427.  
  1428.         }
  1429.       sPrintf(work, "for %s %s.\n ", netBuf.netName,
  1430.       netBuf.nbflags.MassTransfer ? "ON" : "OFF");
  1431.       SysopInfoReport(id, work);
  1432.       if (netBuf.nbflags.MassTransfer)
  1433.         {
  1434.         MakeNetCacheName(temp, thisNet);
  1435.         mkdir(temp);
  1436.  
  1437.         }
  1438.       putNet(thisNet, &netBuf);
  1439.       /* more work here? */
  1440.       break;
  1441.       case 'R':
  1442.       CloseSysopMenu(id);
  1443.       EachSharedRoom(thisNet, DumpRoom, DumpVRoom, NULL);
  1444.       if (onConsole) modIn();
  1445.       sPrintf(title, " Editing %s ", netBuf.netName);
  1446.       id = RegisterSysopMenu("netedit.mnu", NetEditOpts, title);
  1447.       break;
  1448.       case 'N':
  1449.       SysopRequestString(id, "SYSTEM", temp, NAMESIZE, 0);
  1450.       if (strLen(temp) != 0) strCpy(netBuf.netName, temp);
  1451.       if (SysopGetYesNo(id, NULL, "NEWSYS"))
  1452.         {
  1453.         netBuf.nbGen = (netBuf.nbGen + 1) % NET_GEN;
  1454.         KillTempFiles(thisNet);
  1455.         ClearRoomSharing();
  1456.  
  1457.         }
  1458.       break;
  1459.       case 'I':
  1460.       SysopRequestString(id, "SYSTID", temp, NAMESIZE, 0);
  1461.       if (strLen(temp) != 0) strCpy(netBuf.netId, temp);
  1462.       if (SysopGetYesNo(id, NULL, "NEWSYS"))
  1463.         {
  1464.         netBuf.nbGen = (netBuf.nbGen + 1) % NET_GEN;
  1465.         KillTempFiles(thisNet);
  1466.         ClearRoomSharing();
  1467.  
  1468.         }
  1469.       break;
  1470.       case 'K':
  1471.       if (netBuf.nbflags.normal_mail)
  1472.         {
  1473.         sPrintf(work, "There is outgoing mail outstanding.\n ");
  1474.         SysopInfoReport(id, work);
  1475.  
  1476.         }
  1477.       if (netBuf.nbflags.room_files)
  1478.         {
  1479.         sPrintf(work, "There are file requests outstanding.\n ");
  1480.         SysopInfoReport(id, work);
  1481.  
  1482.         }
  1483.       if (SysopGetYesNo(id, NULL, "CONFRM"))
  1484.         {
  1485.         netBuf.nbflags.in_use = FALSE;
  1486.         putNet(place, &netBuf);
  1487.         KillTempFiles(thisNet);
  1488.         KillCacheFiles(thisNet);
  1489.         CloseSysopMenu(id);
  1490.         return;
  1491.  
  1492.         }
  1493.       break;
  1494.       case 'L':
  1495.       netBuf.nbflags.local = SysopGetYesNo(id, NULL, "ISSYSL");
  1496.       break;
  1497.       case 'P':
  1498.       CloseSysopMenu(id);
  1499.       Output_Citadel_Message("NTPSWO",
  1500.                              (long)netBuf.OurPwd,
  1501.                              (long)netBuf.TheirPwd, NULL);
  1502.       if (getXString("NTNPWO", temp2, NAMESIZE, "", ""))
  1503.       strCpy(netBuf.OurPwd, temp2);
  1504.       if (getXString("NTNPWT", temp2, NAMESIZE, "", ""))
  1505.       strCpy(netBuf.TheirPwd, temp2);
  1506.       id = RegisterSysopMenu("netedit.mnu", NetEditOpts, title);
  1507.       break;
  1508.       case 'M':
  1509.       getList(addNetMem, "Nets to add to this system's member list",
  1510.       5, TRUE);
  1511.       getList(subNetMem,"Nets to take off this system's member list",
  1512.       5, TRUE);
  1513.       break;
  1514.       case 'S':
  1515.       Output_Citadel_Message("ISPINE",(long)netBuf.netName,NULL,NULL);
  1516.       if (!(netBuf.nbflags.spine = SysopGetYesNo(id, NULL, "CONFRM")))
  1517.         {
  1518.         Output_Citadel_Message("SPINEU",(long)netBuf.netName,NULL,NULL);
  1519.         netBuf.nbflags.is_spine =
  1520.         SysopGetYesNo(id, NULL, "CONFRM");
  1521.  
  1522.         }
  1523.       else
  1524.       netBuf.nbflags.is_spine = FALSE;
  1525.       break;
  1526.       case 'O':
  1527.       Output_Citadel_Message((netBuf.nbflags.OtherNet) ? "NOTHER" : "OTHERN",NULL, NULL, NULL);
  1528.       netBuf.nbflags.OtherNet = !netBuf.nbflags.OtherNet;
  1529.       break;
  1530.       case 'V':
  1531.       NodeValues(id);
  1532.       break;
  1533.       #ifdef NEEDED
  1534.       case 'Z':
  1535.       netBuf.nbHiRouteInd = (int) getNumber("KLUDGE", 0l, 255l);
  1536.       netBuf.nbflags.HasRouted = TRUE;
  1537.       break;
  1538.       #endif
  1539.  
  1540.       }
  1541.  
  1542.     }
  1543.  
  1544.   }
  1545. /*
  1546. * KillTempFiles()
  1547. *
  1548. * This eliminates unneeded temp files for dead node.
  1549. */
  1550. void KillTempFiles(int which)
  1551.   {
  1552.   label    temp;
  1553.   SYS_FILE temp2;
  1554.   sPrintf(temp, "%d.ml", which);
  1555.   makeSysName(temp2, temp, &cfg.netArea);
  1556.   unlink(temp2);
  1557.   netBuf.nbflags.normal_mail = FALSE;
  1558.   sPrintf(temp, "%d.rfl", which);
  1559.   makeSysName(temp2, temp, &cfg.netArea);
  1560.   unlink(temp2);
  1561.   netBuf.nbflags.room_files = FALSE;
  1562.   sPrintf(temp, "%d.sfl", which);
  1563.   makeSysName(temp2, temp, &cfg.netArea);
  1564.   unlink(temp2);
  1565.   netBuf.nbflags.send_files = FALSE;
  1566.   sPrintf(temp, "%d.vtx", which);
  1567.   makeSysName(temp2, temp, &cfg.netArea);
  1568.   unlink(temp2);
  1569.   InitVNode(thisNet);
  1570.  
  1571.   }
  1572. /*
  1573. * ClearRoomSharing()
  1574. *
  1575. * This clears room sharing out completely for this node.
  1576. */
  1577. void ClearRoomSharing()
  1578.   {
  1579.   int i;
  1580.   for (i = 0; i < SHARED_ROOMS; i++)
  1581.   netBuf.netRooms[i].srgen = 0;
  1582.  
  1583.   }
  1584. /*
  1585. * NodeValues()
  1586. *
  1587. * This function prints out the values for the current node.
  1588. */
  1589. void NodeValues(MenuId id)
  1590.   {
  1591.   int i, first;
  1592.   MULTI_NET_DATA h;
  1593.   sPrintf(msgBuf.mbtext, "\n Node #%d: %s", thisNet, netBuf.netName);
  1594.   if (strLen(netBuf.nbShort))
  1595.   sPrintf(lbyte(msgBuf.mbtext), " (%s)", netBuf.nbShort);
  1596.   sPrintf(lbyte(msgBuf.mbtext), "\n Id: %s (%slocal @ %s)\n ",
  1597.   netBuf.netId,
  1598.   netBuf.nbflags.local ? "" : "non",
  1599.   SupportedBauds[netBuf.baudCode]);
  1600.   if (netBuf.nbflags.ExternalDialer)
  1601.   sPrintf(lbyte(msgBuf.mbtext), "External Dialer Information: %s\n ", netBuf.access);
  1602.   if (strLen(netBuf.access) != 0 && !netBuf.nbflags.ExternalDialer)
  1603.   sPrintf(lbyte(msgBuf.mbtext), "Access: %s\n ", netBuf.access);
  1604.   if (netBuf.nbflags.spine)
  1605.   sPrintf(lbyte(msgBuf.mbtext), "We are a spine for this system\n ");
  1606.   else if (netBuf.nbflags.is_spine)
  1607.   sPrintf(lbyte(msgBuf.mbtext), "This system is a spine\n ");
  1608.   if (netBuf.nbflags.OtherNet)
  1609.   sPrintf(lbyte(msgBuf.mbtext), "This system is designated as OtherNet.\n ");
  1610.   if (netBuf.nbflags.normal_mail)
  1611.   sPrintf(lbyte(msgBuf.mbtext), "There is outgoing Mail>.\n ");
  1612.   if (netBuf.nbflags.HasRouted)
  1613.   sPrintf(lbyte(msgBuf.mbtext), "There is outgoing RouteMail.\n ");
  1614.   if (DomainFlags[thisNet])
  1615.   sPrintf(lbyte(msgBuf.mbtext), "There is outgoing DomainMail.\n ");
  1616.   if (netBuf.nbflags.room_files)
  1617.   sPrintf(lbyte(msgBuf.mbtext), "There are file requests outstanding.\n ");
  1618.   if (netBuf.nbflags.send_files)
  1619.   sPrintf(lbyte(msgBuf.mbtext), "There are files to be sent.\n ");
  1620.   if (netBuf.nbflags.MassTransfer)
  1621.   sPrintf(lbyte(msgBuf.mbtext), "Fast Transfers on (using %s).\n ",
  1622.   GetCompEnglish(GetCompression(thisNet)));
  1623.   if (netBuf.MemberNets != 0l)
  1624.     {
  1625.     sPrintf(lbyte(msgBuf.mbtext), "This system is assigned to the following nets: ");
  1626.     for (i = 0, first = 1, h = 1l; i < MAX_NET; i++)
  1627.       {
  1628.       if (h & netBuf.MemberNets)
  1629.         {
  1630.         if (!first)
  1631.         sPrintf(lbyte(msgBuf.mbtext), ", ");
  1632.         else first = FALSE;
  1633.         sPrintf(lbyte(msgBuf.mbtext), "%d", i+1); /* Yes - +1. Number the bits starting with 1 */
  1634.  
  1635.         }
  1636.       h <<= 1;
  1637.  
  1638.       }
  1639.     sPrintf(lbyte(msgBuf.mbtext), ".\n ");
  1640.  
  1641.     }
  1642.   else sPrintf(lbyte(msgBuf.mbtext), "This system is currently disabled.\n ");
  1643.   sPrintf(lbyte(msgBuf.mbtext), "Last connected: %s\n", AbsToReadable(netBuf.nbLastConnect));
  1644.   SysopDisplayInfo(id, msgBuf.mbtext, " Values ");
  1645.  
  1646.   }
  1647. /*
  1648. * fileRequest()
  1649. *
  1650. * This handles the administration of requesting files from another system.
  1651. */
  1652. void fileRequest()
  1653.   {
  1654.   struct fl_req file_data;
  1655.   label    data;
  1656.   char     loc[100], *c, *work;
  1657.   SYS_FILE fn;
  1658.   char     abort;
  1659.   FILE     *temp;
  1660.   int      place;
  1661.   extern char *APPEND_ANY;
  1662.   char     ambiguous, again;
  1663.   MenuId   id;
  1664.   place = thisNet;    /* again, a kludge to be killed later */
  1665.   id = SysopContinual("", "", 75, 10);
  1666.   SysopContinualString(id, "ROMNAM", file_data.room, NAMESIZE, 0);
  1667.   if (strLen(file_data.room) == 0)
  1668.     {
  1669.     SysopCloseContinual(id);
  1670.     return;
  1671.  
  1672.     }
  1673.   SysopContinualString(id, "EFILEN", loc, sizeof loc, 0);
  1674.   if (strLen(loc) == 0)
  1675.     {
  1676.     SysopCloseContinual(id);
  1677.     return;
  1678.  
  1679.     }
  1680.   ambiguous = !(strchr(loc, '*') == NULL && strchr(loc, '?') == NULL &&
  1681.   strchr(loc, ' ') == NULL);
  1682.   abort = !netGetAreaV2(id, loc, &file_data, ambiguous);
  1683.   if (!abort)
  1684.     {
  1685.     sPrintf(data, "%d.rfl", place);
  1686.     makeSysName(fn, data, &cfg.netArea);
  1687.     if ((temp = safeopen(fn, APPEND_ANY)) == NULL)
  1688.       {
  1689.       SysopPrintf(id, "Couldn't append to '%s'????", fn);
  1690.  
  1691.       }
  1692.     else
  1693.       {
  1694.       work = loc;
  1695.       do
  1696.         {
  1697.         again = (c = strchr(work, ' ')) != NULL;
  1698.         if (again) *c = 0;
  1699.         strCpy(file_data.roomfile, work);
  1700.         if (ambiguous) strCpy(file_data.filename, work);
  1701.         fwrite(&file_data, sizeof (file_data), 1, temp);
  1702.         if (again) work = c + 1;
  1703.  
  1704.         }
  1705.       while (again);
  1706.       netBuf.nbflags.room_files = TRUE;
  1707.       putNet(place, &netBuf);
  1708.       fclose(temp);
  1709.  
  1710.       }
  1711.  
  1712.     }
  1713.   SysopCloseContinual(id);
  1714.  
  1715.   }
  1716. /*
  1717. * roomsShared()
  1718. *
  1719. * This function returns TRUE if this system has a room with new data to share
  1720. * (orSomething).
  1721. */
  1722. char roomsShared(int slot)
  1723.   {
  1724.   int ROutGoing(SharedRoom *room, int system, int index, int roomslot,void *d);
  1725.   char OutGoing;
  1726.   /* We only want to make one "successful" call per voluntary net session */
  1727.   if ((inNet == UNTIL_NET || inNet == NORMAL_NET || inNet == ANYTIME_NET ) &&
  1728.   pollCall[slot] <= 0)
  1729.   return FALSE;
  1730.   /*
  1731.   * Rules:
  1732.   * We check each slot of the shared rooms list for this node.  For
  1733.   * each one that is in use, we do the following:
  1734.   *   HOSTS ARE OBSOLETE!
  1735.   * a) if we are regional host for the room and other system is
  1736.   *    a backbone, then don't assume we need to call.
  1737.   * b) if we are backboning the room, check to see what status of this
  1738.   *    room for other system is.
  1739.   *    1) If we are Passive Backbone, then we need not call.
  1740.   *    2) If we are Active Backbone, then do call.
  1741.   *    3) The Regional Host looks screwy.  This may be a bug.
  1742.   * c) If none of the above applies, implies we are a simple Peon, so
  1743.   *    we simply check to see if we have outgoing messages, and if so,
  1744.   *    return TRUE indicating that we need to call; otherwise, continue
  1745.   *    search.
  1746.   *
  1747.   * LATER NOTE: now this is split up due to the use of EachSharedRoom.
  1748.   */
  1749.   OutGoing = FALSE;
  1750.   EachSharedRoom(slot, ROutGoing, VRNeedCall, &OutGoing);
  1751.   return OutGoing;
  1752.  
  1753.   }
  1754. /*
  1755. * ROutGoing()
  1756. *
  1757. * This decides if the system in question needs to be called due to the
  1758. * situation of the rooms.
  1759. */
  1760. int ROutGoing(SharedRoom *room, int system, int index, int roomslot, void *d)
  1761.   {
  1762.   char *arg;
  1763.   arg = d;
  1764.   if (roomTab[roomslot].rtShareType != PEON)
  1765.     {
  1766.     if (CGetMode(room->mode) == PASS_BACKBONE)
  1767.     return TRUE;
  1768.     else if (CGetMode(room->mode) == REG_HOST ||
  1769.     CGetMode(room->mode) == ACTIVE_BACKBONE)
  1770.       {
  1771.       if (inNet == NORMAL_NET)
  1772.         {
  1773.         *arg = TRUE;
  1774.         return ERROR;
  1775.  
  1776.         }
  1777.  
  1778.       }
  1779.  
  1780.     }
  1781.   if (roomTab[roomslot].rtlastNet > room->lastMess)
  1782.     {
  1783.     *arg = TRUE;
  1784.     return ERROR;
  1785.  
  1786.     }
  1787.   if (GetFA(room->mode))
  1788.     {
  1789.     *arg = TRUE;
  1790.     return ERROR;
  1791.  
  1792.     }
  1793.   return TRUE;
  1794.  
  1795.   }
  1796. /*
  1797. * DumpRoom()
  1798. *
  1799. * This dumps out information concerning a shared room, such as the status
  1800. * and the message stuff.
  1801. */
  1802. int DumpRoom(SharedRoom *room, int system, int index, int roomslot, void *d)
  1803.   {
  1804.   char cmd, *s1, *s2, *s3, *name, doit;
  1805.   mPrintf("%-22sRelationship: ", roomTab[roomslot].rtname);
  1806.   Addressing(system, index, &cmd, &s1, &s2, &s3, &name, &doit);
  1807.   mPrintf(name);
  1808.   mPrintf(" (last sent=%ld, netlast=%ld)",
  1809.   room->lastMess, roomTab[roomslot].rtlastNet);
  1810.   if (GetFA(netTab[system].netTRooms[index].mode))
  1811.   mPrintf("*");
  1812.   mPrintf("\n ");
  1813.   return TRUE;
  1814.  
  1815.   }
  1816. /*
  1817. * netResult()
  1818. *
  1819. * This will put a message to the net msg holder, building a message for the
  1820. * Aide room.
  1821. */
  1822. void netResult(char *msg)
  1823.   {
  1824.   if (netMsg != NULL)
  1825.     {
  1826.     fprintf(netMsg, "(%s) %s\n\n", Current_Time(), msg);
  1827.     fflush(netMsg);
  1828.     UsedNetMsg = TRUE;
  1829.  
  1830.     }
  1831.  
  1832.   }
  1833. /*
  1834. * netInfo()
  1835. *
  1836. * This function acquires necessary info from the user when entering a message.
  1837. */
  1838. char netInfo(char GetName)
  1839.   {
  1840.   int    cost;
  1841.   extern char *ALL_LOCALS;
  1842.   extern char *R_SH_MARK;
  1843.   label  domain = "";
  1844.   char   sys[NAMESIZE * 2];
  1845.   char   isdomain, *address;
  1846.   char   work[45];
  1847.   if (thisRoom == MAILROOM)
  1848.     {
  1849.     strCpy(sys, msgBuf.mbaddr);
  1850.     if (!ReqNodeName("SYSTSD", sys, domain, (char) aide,
  1851.     FALSE, GetName, FALSE, FALSE, &netBuf))
  1852.     return FALSE;
  1853.     isdomain = (domain[0] != 0);
  1854.     if (strCmpU(sys, ALL_LOCALS) != SAMESTRING)
  1855.       {
  1856.       if (strCmpU(domain, cfg.nodeDomain + cfg.codeBuf) == SAMESTRING &&
  1857.       (strCmpU(sys, cfg.nodeName + cfg.codeBuf) == SAMESTRING ||
  1858.       strCmpU(sys, UseNetAlias(cfg.nodeName+cfg.codeBuf, TRUE))
  1859.       == SAMESTRING))
  1860.         {
  1861.         mPrintf("Hey, that's this system!\n ");
  1862.         return FALSE;
  1863.  
  1864.         }
  1865.       cost = (isdomain) ? FindCost(domain) : !netBuf.nbflags.local;
  1866.       if (logBuf.credit < cost)
  1867.         {
  1868.         if (HalfSysop())
  1869.           {
  1870.           logBuf.credit += cost;
  1871.  
  1872.           }
  1873.         else
  1874.           {
  1875.           Output_Citadel_Message("NOCRDT", NULL, NULL, NULL);
  1876.           return FALSE;
  1877.  
  1878.           }
  1879.  
  1880.         }
  1881.       if (isdomain)
  1882.         {
  1883.         sPrintf(work, "%s _ %s", sys, domain);
  1884.         address = work;
  1885.  
  1886.         }
  1887.       else address = sys;
  1888.       if (!isdomain && netBuf.nbflags.OtherNet)
  1889.         {
  1890.         mPrintf("%s address", netBuf.netName);
  1891.         getNormStr("", msgBuf.mbOther, O_NET_PATH_SIZE, 0);
  1892.         if (strLen(msgBuf.mbOther) == 0) return FALSE;
  1893.  
  1894.         }
  1895.  
  1896.       }
  1897.     else
  1898.       {
  1899.       address = ALL_LOCALS;
  1900.  
  1901.       }
  1902.  
  1903.     }
  1904.   else
  1905.     {
  1906.     if (!roomBuf.rbflags.SHARED)
  1907.       {
  1908.       mPrintf("Sorry, this is not a network room\n ");
  1909.       return FALSE;
  1910.  
  1911.       }
  1912.     address = R_SH_MARK;
  1913.     strCpy(msgBuf.mboname, cfg.codeBuf + cfg.nodeName);
  1914.     strCpy(msgBuf.mbdomain, cfg.codeBuf + cfg.nodeDomain);
  1915.  
  1916.     }
  1917.   strCpy(msgBuf.mbaddr, address);
  1918.   return TRUE;
  1919.  
  1920.   }
  1921. /*
  1922. * killConnection()
  1923. *
  1924. * Zaps carrier for network.
  1925. */
  1926. void killConnection()
  1927.   {
  1928.   HangUp(TRUE);
  1929.   modStat = haveCarrier = FALSE;
  1930.   while (MIReady()) inp();    /* Clear buffer of garbage */
  1931.  
  1932.   }
  1933. /*
  1934. * setPoll()
  1935. *
  1936. * This allows us to make sure we don't poll hosts too often during a net
  1937. * session.
  1938. */
  1939. void setPoll()
  1940.   {
  1941.   int rover;
  1942.   pollCall = GetDynamic(cfg.netSize);
  1943.   for (rover = 0; rover < cfg.netSize; rover++)
  1944.     {
  1945.     pollCall[rover] = 1;
  1946.  
  1947.     }
  1948.  
  1949.   }
  1950. /*
  1951. * makeCall()
  1952. *
  1953. * This handles the actual task of dialing the modem.
  1954. */
  1955. int makeCall(char EchoErr, MenuId id)
  1956.   {
  1957.   char  call[80];
  1958.   label blip1;
  1959.   int   bufc, result;
  1960.   int  safe_baud;      /* make a safe baud rate dial string */
  1961.   char  buf[30], c, viable;
  1962.   char  ourArea[4], targetArea[4];
  1963.   while (MIReady()) inp();
  1964.   AreaCode(netBuf.netId, targetArea);
  1965.   AreaCode(cfg.nodeId + cfg.codeBuf, ourArea);
  1966.   if (!netBuf.nbflags.ExternalDialer)
  1967.     {
  1968.     setNetCallBaud(netBuf.baudCode, "makeCall");
  1969.     normId(netBuf.netId, blip1);
  1970.     safe_baud = minimum(netBuf.baudCode, cfg.sysBaud);
  1971.     if( safe_baud >= MAX_DIAL_STRINGS ) safe_baud = MAX_DIAL_STRINGS - 1;
  1972.     strCpy(call, cfg.codeBuf + cfg.DialPrefixes[safe_baud]);
  1973.     if (strLen(netBuf.access) != 0)
  1974.       {
  1975.       /* don't need to check extdial*/
  1976.       strCat(call, netBuf.access);
  1977.  
  1978.       }
  1979.     else if (!netBuf.nbflags.local)
  1980.       {
  1981.       strCat(call, "1");
  1982.       /* LD within same area code? (courtesy farokh irani) */
  1983.       if (strCmp(targetArea, ourArea) == SAMESTRING)
  1984.       strCat(call, blip1 + 5);
  1985.       else
  1986.       strCat(call, blip1 + 2);
  1987.  
  1988.       }
  1989.     else
  1990.       {
  1991.       /* local but different area codes?  (e.g., NYC) */
  1992.       /* again courtesy farokh irani */
  1993.       if (strCmp(targetArea, ourArea) != SAMESTRING)
  1994.       strCat(call, blip1 + 2);
  1995.       else
  1996.       strCat(call, blip1 + 5);
  1997.  
  1998.       }
  1999.     strCat(call, cfg.codeBuf + cfg.netSuffix);
  2000.     switch (RottenDial(call))
  2001.       {
  2002.       case FALSE: moPuts(call); break;
  2003.       case TRUE:  break;
  2004.       case ERROR: return FALSE;
  2005.  
  2006.       }
  2007.     for (startTimer(WORK_TIMER), bufc = 0, viable = TRUE;
  2008.     chkTimeSince(WORK_TIMER) < ((netBuf.nbflags.local) ? 40l : LD_Delay)
  2009.     && viable;)
  2010.       {
  2011.       if (gotCarrier()) break;
  2012.       /* Parse incoming string from modem -- call progress detection */
  2013.       if (KBReady()) viable = FALSE;
  2014.       if (MIReady())
  2015.         {
  2016.         if ((c = inp()) == '\r')
  2017.           {
  2018.           buf[bufc] = 0;
  2019.           switch ((result = ResultVal(buf)))
  2020.             {
  2021.             case R_NODIAL:
  2022.             case R_NOCARR:
  2023.             case R_BUSY:
  2024.             if( logNetResults )
  2025.               {
  2026.               if (EchoErr ) splitF(netLog, "(%s) ", buf);
  2027.               else SysopPrintf(id, "\n%s", buf);
  2028.               };
  2029.             viable = FALSE; break;
  2030.             case R_300:
  2031.             case R_1200:
  2032.             case R_2400:
  2033.             case R_4800:
  2034.             case R_9600:
  2035.             case R_14400:
  2036.             case R_19200:
  2037.             if ( safe_baud != result )
  2038.               {
  2039.               setNetCallBaud(result,"makeCall");
  2040.               if( logNetResults )splitF(netLog, "(Mismatch: %s, adjusting.)\n", buf);
  2041.  
  2042.               }
  2043.             break;
  2044.  
  2045.             }
  2046.           bufc = 0;
  2047.  
  2048.           }
  2049.         else
  2050.           {
  2051.           if (bufc > 28) bufc = 0;
  2052.           else if (c != '\n')
  2053.             {
  2054.             buf[bufc++] = c;
  2055.  
  2056.             }
  2057.  
  2058.           }
  2059.  
  2060.         }
  2061.       if( viable ) BeNice(INUSE_PAUSE);  /* give up some CPU time */
  2062.  
  2063.       }
  2064.     if (gotCarrier())
  2065.     return TRUE;
  2066.  
  2067.     }
  2068.   else
  2069.     {
  2070.     return DialExternal(&netBuf);
  2071.  
  2072.     }
  2073.   return FALSE;
  2074.  
  2075.   }
  2076. void ExplainNeed(int i, MULTI_NET_DATA x)
  2077.   {
  2078.   char c0,c1,c2;
  2079.   if (!cfg.BoolFlags.debug) return;
  2080.   c0 = netTab[i].ntShort[0];
  2081.   if( !isprint(c0))c0 = ' ';
  2082.   c1 = netTab[i].ntShort[1];
  2083.   c2 = netTab[i].ntShort[2];
  2084.   if( !isprint(c0))c0 = ' ';
  2085.   if( !isprint(c1))c1 = ' ';
  2086.   if( !isprint(c2))c2 = ' ';
  2087.   splitF(netLog," Networking with:( %c%c%c ) \n",c0,c1,c2);
  2088.   splitF(netLog, "slot %d%sin use is%sspine we are%sa spine \n",
  2089.   i, netTab[i].ntflags.in_use      ? " ":" not ",
  2090.   netTab[i].ntflags.is_spine       ? " ":" not ",
  2091.   netTab[i].ntflags.spine          ? " ":" not ");
  2092.   splitF(netLog, " MN%ld has%smail\n",  netTab[i].ntMemberNets & x,
  2093.   netTab[i].ntflags.normal_mail ? " ":" no ");
  2094.   splitF(netLog, "%sfile requests %ssend requests has%srooms to share\n",
  2095.   netTab[i].ntflags.room_files ? " ":" no ",
  2096.   netTab[i].ntflags.send_files ? " ":" no ",
  2097.   roomsShared(i) ? " ":" no ");
  2098.   splitF(netLog, " Domain Flags:%d has%srouted for %s mode \n",
  2099.   DomainFlags[i],
  2100.   netTab[i].ntflags.HasRouted ? " ":" no ",
  2101.   (inNet == NON_NET)    ? "NON_NET":
  2102.   (inNet == NORMAL_NET) ? "NORMAL_NET" :
  2103.   (inNet == ANYTIME_NET)? "ANYTIME_NET" :
  2104.   (inNet == UNTIL_NET)  ? "UNTIL_NET": "UNKNOWN");
  2105.  
  2106.   }
  2107. #define SpineSet(i) (netTab[i].ntflags.is_spine && !(netTab[i].ntMemberNets & PRIORITY_MAIL))
  2108. /*
  2109. * needToCall()
  2110. *
  2111. * This is responsible for checking to see if we need to call this system.
  2112. * Basically, here's what the rules are:
  2113. *
  2114. * Is this account in use?
  2115. * Is this account on one of the eligible net ('x' parameter)?
  2116. * Is this account not a spine and not an OtherNet system?
  2117. *
  2118. * If this system is a spine and we're not doing an anytime-net session
  2119. * and we haven't had a successful connection yet then call.
  2120. *
  2121. * If this system has normal mail, room file requests, send file requests,
  2122. * rooms that need to share (outgoing messages), domain mail outgoing, mail
  2123. * routing and hasn't been connected with yet, then call.
  2124. *
  2125. * I'm not entirely sure what the reference to Priority Mail signifies in
  2126. * this mess.
  2127. */
  2128. int needToCall(int i, MULTI_NET_DATA x)
  2129.   {
  2130.   /* first check for permission to call   */
  2131.   if (netTab[i].ntflags.in_use &&     /* account in use   */
  2132.   (netTab[i].ntMemberNets & x) &&  /* system is member of net      */
  2133.   !SpineSet(i) &&
  2134.   !netTab[i].ntflags.OtherNet)
  2135.     {
  2136.     /* system not OtherNet    */
  2137.     /* check for requirement to call  */
  2138.     if (netTab[i].ntflags.spine &&
  2139.     !(netTab[i].ntMemberNets & PRIORITY_MAIL) &&
  2140.     (inNet == NON_NET || ((inNet == NORMAL_NET || inNet == UNTIL_NET) &&
  2141.     pollCall[i] == 1)))
  2142.     return TRUE;
  2143.     /* now check for need to call     */
  2144.     if (netTab[i].ntflags.normal_mail ||  /* normal outgoing mail?*/
  2145.     netTab[i].ntflags.room_files || /* request files ?  */
  2146.     netTab[i].ntflags.send_files || /* send files ?   */
  2147.     roomsShared(i) ||     /* rooms to share?  */
  2148.     DomainFlags[i] ||     /* domain mail to send? */
  2149.     (netTab[i].ntflags.HasRouted &&
  2150.     (inNet == NON_NET ||
  2151.     ((inNet == NORMAL_NET || inNet == ANYTIME_NET ||
  2152.     inNet == UNTIL_NET) &&
  2153.     pollCall[i] == 1))))
  2154.     return TRUE;
  2155.  
  2156.     }
  2157.   return FALSE;
  2158.  
  2159.   }
  2160. /*
  2161. * AnyCallsNeeded()
  2162. *
  2163. * Do we need to make any calls 'tall?
  2164. */
  2165. char AnyCallsNeeded(MULTI_NET_DATA whichNets)
  2166.   {
  2167.   int searcher;
  2168.   for (searcher = 0; searcher < cfg.netSize; searcher++)
  2169.   if (needToCall(searcher, whichNets)) return TRUE;
  2170.   return FALSE;
  2171.  
  2172.   }
  2173. /*
  2174. * ReqNodeName()
  2175. *
  2176. * This function is a general request for node name from user.  It supports
  2177. * various options for prompting or not prompting for the name, allowing the
  2178. * input of '&L', allow display of nodelists, etc. (see the code).  The
  2179. * function will validate the choice, query again if appropriate, handle
  2180. * domains, and do a getNet of the node if necessary.
  2181. */
  2182. char ReqNodeName(char *prompt, label target, label domain, char WideSpecValid,
  2183. char Once, char Ask, char Display, char SysopMenu,
  2184. NetBuffer *nBuf)
  2185.   {
  2186.   extern char *ALL_LOCALS;
  2187.   char sysname[2 * NAMESIZE], dup, work[2 * NAMESIZE];
  2188.   int  slot;
  2189.   if (cfg.BoolFlags.debug)
  2190.      splitF(NULL, " ReqNodeName(%s,%s,%s,%s,%s,%s,%s,%08lx);\n"
  2191.         , (prompt) ? prompt : "NULL",(domain)?domain:"NULL"
  2192.         , (WideSpecValid==TRUE)?"T":"F", (Once==TRUE)?"T":"F"
  2193.         , (Ask==TRUE)?"T":"F", (Display==TRUE)?"T":"F"
  2194.         , (SysopMenu==TRUE)?"T":"F", nBuf);
  2195.  
  2196.   do
  2197.     {
  2198.     slot = ERROR;
  2199.     if (domain != NULL) domain[0] = 0;
  2200.     /* Allows function to act as validator only */
  2201.     if (Ask)
  2202.       {
  2203.       getString(prompt, sysname, 2 * NAMESIZE, QUEST_SPECIAL);
  2204.  
  2205.       }
  2206.     else strCpy(sysname, target);
  2207.     NormStr(sysname);
  2208.     /* Empty line implies operation abort. */
  2209.     if (strLen(sysname) == 0)
  2210.       {
  2211.       strCpy(target, sysname);
  2212.       return FALSE;
  2213.  
  2214.       }
  2215.     /* If "&L" entered and is acceptable ... */
  2216.     if (WideSpecValid && strCmpU(sysname, ALL_LOCALS) == SAMESTRING)
  2217.       {
  2218.       strCpy(target, sysname);
  2219.       return TRUE;
  2220.  
  2221.       }
  2222.     /* Questioning frown */
  2223.     if (cfg.BoolFlags.debug)
  2224.      splitF(NULL, " sysname:%s target:%s\n", sysname, nBuf->netName);
  2225.  
  2226.     if (sysname[0] == '?')
  2227.       {
  2228.       writeNet(Display, FALSE);   /* write out available nets */
  2229.       if (WideSpecValid)
  2230.       mPrintf("'&L' == Local Systems Announcement\n ");
  2231.  
  2232.       }
  2233.     /* finally, must be real system name so seeeeearch for it! */
  2234.     else if ((slot = searchNameNet(sysname, nBuf)) != ERROR)
  2235.       {
  2236.       strCpy(target, nBuf->netName);  /* aesthetics */
  2237.       if (nBuf->nbflags.local || nBuf->nbflags.RouteLock)
  2238.         {
  2239.         return TRUE;    /* Yup */
  2240.  
  2241.         }
  2242.  
  2243.       }
  2244.     if (domain != NULL && SystemInSecondary(sysname, domain, &dup))
  2245.       {
  2246.       if (dup)
  2247.         {
  2248.         /* oops */
  2249.         if (slot != ERROR) return TRUE;
  2250.         /* do it as a double if, not claused */
  2251.         if (Ask)
  2252.           Output_Citadel_Message("DUPDOM", (long)sysname, NULL, NULL);
  2253.  
  2254.         }
  2255.       else
  2256.         {
  2257.         strCpy(target, sysname);  /* aesthetics */
  2258.         return TRUE;
  2259.  
  2260.         }
  2261.  
  2262.       }
  2263.     if (slot != ERROR) return TRUE;
  2264.     if (sysname[0] != '?')
  2265.       {
  2266.       sPrintf(work, "%s not listed.\n", sysname); /* Nope */
  2267.       if (SysopMenu) SysopError(NO_MENU, work);
  2268.       else     mPrintf(work);
  2269.  
  2270.       }
  2271.  
  2272.     }
  2273.   while (!Once && Ask); /* This controls if we ask repeatedly or only once */
  2274.   return FALSE;       /* And if we get here, we definitely are a failure */
  2275.  
  2276.   }
  2277. /*
  2278. * NetValidate()
  2279. *
  2280. * This will return TRUE if net privs are go, FALSE otherwise.
  2281. */
  2282. char NetValidate(char talk)
  2283.   {
  2284.   if (!cfg.BoolFlags.netParticipant)
  2285.     {
  2286.     if (talk)
  2287.       Output_Citadel_Message("NTPTNT",NULL, NULL, NULL);
  2288.     return FALSE;
  2289.  
  2290.     }
  2291.   if( loggedIn && logBuf.lbflags.NET_PRIVS ) return TRUE;
  2292.   if( loggedIn && roomBuf.rbflags.AUTO_NET ) return TRUE;
  2293.   if( loggedIn && roomBuf.rbflags.ALL_NET  ) return TRUE;
  2294.   if (talk)
  2295.     Output_Citadel_Message("NTPTNT",NULL, NULL, NULL);
  2296.   return FALSE;
  2297.   }
  2298. /*
  2299. * FindRouteIndex()
  2300. *
  2301. * This will find the next route filename in sequence.
  2302. */
  2303. int FindRouteIndex(int slot)
  2304.   {
  2305.   label temp;
  2306.   SYS_FILE newfn;
  2307.   sPrintf(temp, "R%d", slot);
  2308.   makeSysName(newfn, temp, &cfg.netArea);
  2309.   return FindNextFile(newfn);
  2310.  
  2311.   }
  2312. typedef struct
  2313.   {
  2314.   int count;
  2315.   char *str;
  2316.  
  2317.   }
  2318. SR_Arg;
  2319. /*
  2320. * ParticipatingNodes()
  2321. *
  2322. * This function prepares a string indicating who shares the current room with
  2323. * us.
  2324. */
  2325. void ParticipatingNodes(char *target)
  2326.   {
  2327.   int    node;
  2328.   SR_Arg arg;
  2329.   char   *c;
  2330.   int ShowSharedRoomName(SharedRoom *room, int system, int index,
  2331.   int roomslot, void *arg);
  2332.   sPrintf(lbyte(target), ". This room is shared with: ");
  2333.   arg.count = 0;
  2334.   arg.str   = target;
  2335.   for (node = 0; node < cfg.netSize; node++)
  2336.   EachSharedRoom(node, ShowSharedRoomName, NULL, &arg);
  2337.   if (arg.count)
  2338.     {
  2339.     /* this eliminates the trailing comma */
  2340.     c = lbyte(target);
  2341.     c -= 2;
  2342.     *c = 0;
  2343.  
  2344.     }
  2345.  
  2346.   }
  2347. /*
  2348. * ShowSharedRoomName()
  2349. *
  2350. * This appends the name of this shared room to a string.
  2351. */
  2352. int ShowSharedRoomName(SharedRoom *room, int system, int index, int roomslot,
  2353. void *d)
  2354.   {
  2355.   SR_Arg *arg;
  2356.   char *name;
  2357.   char commnd, *s1, *s2, *s3, doit;
  2358.   arg = d;
  2359.   if (roomslot == thisRoom)
  2360.     {
  2361.     getNet(system, &netBuf);
  2362.     arg->count++;
  2363.     Addressing(system, index, &commnd, &s1, &s2, &s3, &name, &doit);
  2364.     sPrintf(lbyte(arg->str), "%s (%s), ", netBuf.netName, name);
  2365.     return ERROR;
  2366.  
  2367.     }
  2368.   return TRUE;
  2369.  
  2370.   }
  2371. /*
  2372. * AreaCode()
  2373. *
  2374. * This function extracts the area code from the node id.
  2375. */
  2376. void AreaCode(char *Id, char *Target)
  2377.   {
  2378.   int i, j;
  2379.   for (i = j = 0; j < 3 && Id[i]; i++)
  2380.   if (isdigit(Id[i]))
  2381.   Target[j++] = Id[i];
  2382.   Target[j] = 0;
  2383.  
  2384.   }
  2385. /*
  2386. * NetInit()
  2387. *
  2388. * This function does network initialization: Cache handling, network recovery
  2389. * (in case of crash during netting), etc...
  2390. */
  2391. void NetInit()
  2392.   {
  2393.   int rover;
  2394.   char buf[2*NAMESIZE];
  2395.   SpecialMessage("Network Initialization");
  2396.   MakeNetCache(buf);
  2397.   if (access(buf, 0) != 0) mkdir(buf);
  2398.   VirtInit();
  2399.   VortexInit();
  2400.   /* we never need do this again */
  2401.   normId(cfg.codeBuf + cfg.nodeId, HomeId);
  2402.   DomainInit(TRUE);
  2403.   for (rover = 0; rover < cfg.netSize; rover++)
  2404.   if (netTab[rover].ntMemberNets & PRIORITY_MAIL) PriorityMail++;
  2405.   RecoverNetwork();
  2406.   SpecialMessage("");
  2407.  
  2408.   }
  2409. /*
  2410. * MakeNetted()
  2411. *
  2412. * This function will make a message into a net message.  This is userland
  2413. * code called when an aide wants to make a non-netted message into a netted
  2414. * message.
  2415. */
  2416. char MakeNetted(int m)
  2417.   {
  2418.   if (findMessage(roomBuf.msg[m].rbmsgLoc, roomBuf.msg[m].rbmsgNo, TRUE))
  2419.     {
  2420.     getMsgStr(getMsgChar, msgBuf.mbtext, MAXTEXT);  /* get balance */
  2421.     strCpy(msgBuf.mboname, cfg.codeBuf + cfg.nodeName);
  2422.     strCpy(msgBuf.mbdomain, cfg.codeBuf + cfg.nodeDomain);
  2423.     strCpy(msgBuf.mbaddr, R_SH_MARK);
  2424.     DelMsg(TRUE, m);
  2425.     putMessage(NULL);
  2426.     return NETTED;
  2427.  
  2428.     }
  2429.   return NO_CHANGE;
  2430.  
  2431.   }
  2432. /*
  2433. * freeUNS()
  2434. *
  2435. * This function is purportedly a free function for a list.  In actuality,
  2436. * it also runs a net session for each.
  2437. */
  2438. void freeUNS(TwoNumbers *netdata)
  2439.   {
  2440.   int yr, dy, hr, mn, mon, secs, milli;
  2441.   if (!onLine())
  2442.     {
  2443.     getRawDate(&yr, &mon, &dy, &hr, &mn, &secs, &milli);
  2444.     netController((hr * 60) + mn, (int) netdata->second,
  2445.     (1l << (netdata->first - 1)), UNTIL_NET, 0);
  2446.  
  2447.     }
  2448.   free(netdata);
  2449.  
  2450.   }
  2451. /*
  2452. * GetCompression()
  2453. *
  2454. * Gets the compression value.
  2455. */
  2456. int GetCompression(int system)
  2457.   {
  2458.   if (netTab[system].ntflags.Arc) return ARC_COMP;
  2459.   if (netTab[system].ntflags.Zoo) return ZOO_COMP;
  2460.   if (netTab[system].ntflags.Zip) return ZIP_COMP;
  2461.   return LHA_COMP;
  2462.  
  2463.   }
  2464. /*
  2465. * HasOutgoing()
  2466. *
  2467. * This function checks to see if the given room as specified by the system,
  2468. * index pair has outgoing messages in either cache or message form.
  2469. *
  2470. * NB: This code may not be OK.
  2471. */
  2472. char HasOutgoing(int system, int index)
  2473.   {
  2474.   if (GetFA(netTab[system].netTRooms[index].mode)) return TRUE;
  2475.   if (roomTab[netTabRoomSlot(system, index)].rtlastMessage >
  2476.   netTab[system].netTRooms[index].lastMess) return TRUE;
  2477.   return FALSE;
  2478.  
  2479.   }
  2480.